package com.dycong.common.IO.netty.uptime;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoop;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

import java.util.concurrent.TimeUnit;

/**
 * Created by dycong on 2017/4/6.
 */
public class UptimeClientHandler extends SimpleChannelInboundHandler<Object> {
    long startTime = -1;

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelInactive();
        println("Disconnect from>>>>>>" + ctx.channel().remoteAddress());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelActive();
        if (startTime < 0) {
            startTime = System.currentTimeMillis();
            println("Connect to >>>>>>>>>" + ctx.channel().remoteAddress());
        }
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        println("Unregistered%n"+"Sleeping for: "+UptimeClient.RECONNECT_DELAY+"s");
        //// TODO: 2017/4/6 每个Channel持有一个EventLoop>>>AbstractChannel:private volatile EventLoop eventLoop;,EvenLoop是EvenLoopGroup的子类，所以可以直接传入
        // TODO: 2017/4/6 在 Netty 中，一个 ChannelHandler 实例从始至终都是被一个线程调用。所以一个 ChannelHandler 实例肯定也不会被多个线程同时调用 
        final EventLoop loop=ctx.channel().eventLoop();
        loop.schedule(new Runnable() {
            @Override
            public void run() {
//                Bootstrap b0 =UptimeClient.configureBootstrap(new Bootstrap(),loop);
                UptimeClient.connect(UptimeClient.configureBootstrap(new Bootstrap(),loop));
            }
        },UptimeClient.RECONNECT_DELAY, TimeUnit.SECONDS);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (!(evt instanceof IdleStateEvent)) {
            return;
        }
        IdleStateEvent i = (IdleStateEvent) evt;
        if (i.state()== IdleState.READER_IDLE){
            println("Disconnecting due to no inbound traffic");
            ctx.close();
        }
        if (i.state()==IdleState.WRITER_IDLE){
            println("Disconnecting due to no outbound traffic");
            ctx.close();
        }
        if (i.state()==IdleState.ALL_IDLE){
            println("Disconnecting due to no outbound anf inbound traffic");
            ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        ctx.close();
    }


    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        //do nothing
        println("read something...");
    }

    void println(String msg) {
        if (startTime < 0) {
            System.err.format("[SERVER IS DOWN] %s%n", msg);
        } else {
            System.err.format("[UPTIME: %5ds] %s%n", (System.currentTimeMillis() - startTime) / 1000, msg);
        }
    }

}
